/*
 * @Description:
 * @Author: fhw
 * @Date: 2022-08-02 14:41:43
 */
import { forwardRef, HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets'
import { equals, isEmpty, isNil } from 'ramda'
import { ChatUserFriendsService } from 'src/chat_user_friends/chat_user_friends.service'
import { ConfigService } from 'src/socket/config/config.service'
import { SocketMessageGateway } from 'src/socket/socket-message/socket-message.gateway'
import { throwHttp } from 'src/utlis'
import { In, Repository, Server } from 'typeorm'
import { ChatUserService } from '../chat_user/chat_user.service'
import { CreateSysMessageDto, GetSysMessageInfoDto, UpdateSysMessageDto } from './dto/sys_message.dto'
import { SysMessage } from './entities/sys_message.entity'

@Injectable()
@WebSocketGateway()
export class SysMessageService {
  @WebSocketServer() server: any
  constructor(
    @InjectRepository(SysMessage)
    private sysMessageRepository: Repository<SysMessage>,
    @Inject(forwardRef(() => ChatUserService))
    private readonly chatUserServiceRepository: ChatUserService,
    @Inject(forwardRef(() => ConfigService))
    public readonly configService: ConfigService,
  ) { }
  async getSysMessageList({ userId }: { userId: number }) {
    try {
      const [data, total] = await this.sysMessageRepository.findAndCount({
        where: {
          toUserId: userId
        },
        order: { createDate: 'DESC' },
        cache: true,
        relations: ['toUser', 'created']
      });
      return {
        data: data.map(item => {
          item.toUser = {
            username: item.toUser.username,
            headimgurl: item.toUser.headimgurl
          } as any
          item.created = {
            username: item.created.username,
            headimgurl: item.created.headimgurl
          } as any
          return {
            ...item,
          }
        }),
        total,
        success: true,
        code: 200
      }
    } catch (error) {
      return {
        data: error.message,
        code: HttpStatus.BAD_REQUEST,
        success: false
      }
    }
  }
  async createSysMessage(createSysMessageDto: CreateSysMessageDto): Promise<SysMessage> {
    try {
      const { message_title, message_content, message_type, toUserId, userId, status } = createSysMessageDto
      const user = await this.chatUserServiceRepository.getUserInfo({ id: userId })
      const to_user = await this.chatUserServiceRepository.getUserInfo({ id: toUserId })
      const messageInfo = await this.sysMessageRepository.findOne({
        where: { message_type, toUserId, createdId: userId, message_title },
      })
      // 判断是否已有通知消息
      if (!isNil(messageInfo) && !equals(messageInfo.status, 2)) {
        // 更新已有通知消息
        const { affected } = await this.sysMessageRepository
          .createQueryBuilder()
          .update('sys_message')
          .set({ message_status: 0, status: 0, createDate: new Date() })
          .where('id = :id', { id: messageInfo.id })
          .execute()
        if (affected) {
          this.messageNotification(toUserId)
          return messageInfo
        }
        throw new HttpException(
          {
            status: HttpStatus.BAD_REQUEST,
            message: '更新消息通知失败',
          },
          HttpStatus.BAD_REQUEST,
        )
      }
      // 创建消息通知
      const messageData = new SysMessage()
      messageData.message_title = message_title
      messageData.message_content = message_content
      messageData.message_type = message_type
      messageData.toUser = to_user
      messageData.createdName = user.account
      messageData.created = user
      messageData.status = status
      const result = await this.sysMessageRepository.manager.save(messageData)
      if (!isEmpty(result)) {
        this.messageNotification(toUserId)
        return result
      }
      throw new HttpException(
        {
          status: HttpStatus.BAD_REQUEST,
          message: '创建消息通知失败',
        },
        HttpStatus.BAD_REQUEST,
      )
    } catch (error) {
      throwHttp(error.message)
    }
  }
  async updateSysMessage(updateSysMessageDto: UpdateSysMessageDto): Promise<{
    message: string
    success: boolean
  }> {
    try {
      const { status, id, message_title, message_content } = updateSysMessageDto
      const data = await this.sysMessageRepository.findOne({ where: { id } })
      if (isNil(data)) {
        throw new HttpException(
          {
            status: HttpStatus.BAD_REQUEST,
            message: '系统消息不存在',
          },
          HttpStatus.BAD_REQUEST,
        )
      }
      const { affected } = await this.sysMessageRepository
        .createQueryBuilder()
        .update('sys_message')
        .set({ status, message_title, message_content })
        .where('id = :id', { id })
        .execute()
      if (affected) {
        this.messageNotification(data.toUserId)
        return {
          success: true,
          message: '更新成功',
        }
      }
      throw new HttpException(
        {
          status: HttpStatus.BAD_REQUEST,
          message: '更新失败',
        },
        HttpStatus.BAD_REQUEST,
      )
    } catch (error) {
      throwHttp(error.message)
    }
  }
  async getSysMessageInfo(getSysMessageInfoDto: GetSysMessageInfoDto) {
    try {
      const { toUserId, userId, id } = getSysMessageInfoDto
      return await this.sysMessageRepository.findOne({ where: { toUserId, createdId: userId, id } })
    } catch (error) {
      throwHttp(error.message)
    }
  }
  /**
   * 消息通知
   * @param userId 用户id
   */
  async messageNotification(userId: number) {
    const socketId = this.configService.getChatUser(String(userId))
    if (socketId) {
      const { data: sysMessageList } = await this.getSysMessageList({ userId })
      this.server.in(socketId).emit('message', sysMessageList);
    }
  }
  // 设置消息通知已读
  async setSysMessageStatus(ids: string[]) {
    try {
      const { affected } = await this.sysMessageRepository
        .createQueryBuilder()
        .update('sys_message')
        .set({ message_status: 1 })
        .where({ id: In(ids) })
        .execute()
      if (affected) {
        return {
          success: true,
          message: '更新成功',
        }
      }
    } catch (error) {
      return {
        success: false,
        message: error.message, 
      }
    }
  }
}
